package org.az.netty_study.p11_netty的黏包与半包;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.net.InetSocketAddress;

/**
 * 客户端发送完数据后，就会断开连接
 * 服务端就会产生一次可读事件，读到-1，那么在此之前该channel上读到的所有数据，就可以视为一条完整数据
 * 这种方式的消息边界：从连接建立到断开，这中间发送的所有数据视为一条完整数据
 * 这种方式可以解决黏包，因为发完一次消息客户端就断开连接了
 * 但是无法解决半包，因为可能客户端一次发送消息量太大，服务端得分几次来消化
 */
public class _3_黏包半包的解决之短连接 {
    public static void main(String[] args) {

        /**
         * 客户端发送10次消息
         * 观察服务端日志，发现接收到了10条数据，每条都是16B，说明没有发生黏包现象
         * 但这种方案无法解决半包问题
         */
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10; i++) {
            sb.append("a").append(i);
            sendMsg(sb.toString());
        }
    }

    /**
     * 发送一次消息，就断开连接
     */
    private static void sendMsg(String msg) {
        NioEventLoopGroup group = new NioEventLoopGroup();
        Bootstrap client = new Bootstrap()
                .group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {

                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                            //连接建立后,会回调channel上的所有入站handler，并回调他们的channelActive方法发送数据
                            //使用前面的sync也可以在连接建立后发送数据
                            @Override
                            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                /**
                                 * 连接建立后，马上发送消息，然后断开，视为发送一次完整消息
                                 */
                                ByteBuf buf = ctx.alloc().buffer(10);
                                buf.writeBytes(msg.getBytes());
                                ctx.writeAndFlush(buf);
                                ctx.channel().close();
                            }
                        });
                    }
                });
        ChannelFuture channelFuture = client.connect(new InetSocketAddress("localhost", 7777));
        channelFuture.channel().closeFuture().addListener(ch -> {
            group.shutdownGracefully();
        });
    }
}
